#include "GameBoardSolver.h"
#include <QTimer>
#include <QtAlgorithms>
#include <QDebug>
#include <cstdlib>

GameBoardSolver::GameBoardSolver(GameBoard *board)
  : QThread(),
    mOriginalBoard(board),
    mBackTracks(0)
{
}

GameBoardSolver::~GameBoardSolver() {}

void GameBoardSolver::run()
{
  bool solved = solve();
  emit done(solved);
}

void GameBoardSolver::setParameters(float clusterSize, float choicesLeft,
                                    float columnHeight, float singletons,
                                    float histogram)
{
  mClusterSize = clusterSize;
  mChoicesLeft = choicesLeft;
  mColumnHeight = columnHeight;
  mSingletons = singletons;
  mHistogram = histogram;
}

const unsigned long long& GameBoardSolver::getNumBackTracks() const
{
  return mBackTracks;
}

const QList<GameBoard::Choice>& GameBoardSolver::getChoices() const
{
  return mChoicesMade;
}

void GameBoardSolver::scoreAndSortChoices(QList<GameBoard::Choice> & choices)
{
  // Randomize the array to remove initial bias
  for (int i(0); i<choices.count(); ++i)
    for (int j(0); j<choices.count(); ++j)
      if (rand()%2)
        choices.swap(i,j);

  float tiles = mOriginalBoard->rows()*mOriginalBoard->cols();
  foreach (GameBoard::Choice c, choices)
  {
    GameBoard gb(*mOriginalBoard);
    gb.clickAt(QPoint(c.mColumn, c.mRow));
    c.mScore = mClusterSize * c.mRemovedBlocks/tiles;
    c.mScore += mSingletons * gb.getNumSingletons()/tiles;
    //c.mScore += m
  }

  qStableSort(choices);
}

bool GameBoardSolver::solve()
{
  mChoicesMade.clear();
  mBackTracks = 0;
  bool solved = false;
  if (mOriginalBoard == NULL) solved = false;
  else
  {
    mCurrentBoard = new GameBoard(*mOriginalBoard);
    solved = recursiveSolve(mOriginalBoard);
    *mOriginalBoard = *mCurrentBoard;
    delete mCurrentBoard;
    mCurrentBoard = NULL;
  }
  return solved;
}

bool GameBoardSolver::recursiveSolve(GameBoard *board)
{
  if (board->getRemainingTiles() == 0) return true;
  QList<GameBoard::Choice> choices = board->getChoiceList();
  scoreAndSortChoices(choices);
  while (!choices.isEmpty())
  {
    GameBoard::Choice c = choices.back();
    GameBoard gb(*board);
    gb.clickAt(QPoint(c.mColumn, c.mRow));
    *mOriginalBoard = gb;
    if (!recursiveSolve(&gb))
    {
      ++mBackTracks;
      choices.pop_back();
    }
    else
    {
      mChoicesMade << c;
      return true;
    }
  }
  return false;
}
